#include "DataLoader.h"

DataLoader::DataLoader() {

}

std::vector<ColoredVertex*> DataLoader::loadColorVertices(World *pWorld) {
	std::vector<ColoredVertex*> vertexList = std::vector<ColoredVertex*>();
	std::map<int, Land*> lands = pWorld->getLands();
	const UINT VERTICES_PER_TILE = 4;
	const float TILE_SIZE = TurnsDataModel::MAP_TILE_SIZE;
	ColoredVertex *result = new ColoredVertex[lands.size() * VERTICES_PER_TILE];
	
	std::map<int, Land*>::iterator it;
	UINT index = 0;
	for (it = lands.begin(); it != lands.end(); ++it, ++index) {
		Land *land = it->second;

		for (UINT i = 0; i < VERTICES_PER_TILE; ++i) {
			result[index * VERTICES_PER_TILE + i].color = land->color;
		}
		result[index * VERTICES_PER_TILE].position = XMFLOAT3(0.0f, 0.0f, 0.0f);
		result[index * VERTICES_PER_TILE + 1].position = XMFLOAT3(0.0f, 0.0f, TILE_SIZE);
		result[index * VERTICES_PER_TILE + 2].position = XMFLOAT3(TILE_SIZE, 0.0f, TILE_SIZE);
		result[index * VERTICES_PER_TILE + 3].position = XMFLOAT3(TILE_SIZE, 0.0f, 0.0f);
	}
	for (UINT index = 0; index < lands.size() * VERTICES_PER_TILE; ++index) {
		vertexList.push_back(&result[index]);
	}
	return vertexList;
}

World * DataLoader::loadWorld(TCHAR *pFullPath) {
	World *world = new World();
	loadPredefinedLands(world);

	bool success = true;
	std::string line;
	char character;
	std::ifstream loadStream = std::ifstream(pFullPath);
	while (std::getline(loadStream, line) && success) {
		std::istringstream iss(line);
		if (iss >> character) {
			switch (character) {
			case TurnsDataModel::LOADER_COMMENT_CHARACTER:
				break;
			case TurnsDataModel::LOADER_CORNER_CHARACTER:
				success = loadCorner(world, iss);
				break;
			case TurnsDataModel::LOADER_LAND_CHARACTER:
				success = loadLand(world, iss);
				break;
			case TurnsDataModel::LOADER_OBJECT_CHARACTER:
				success = loadObject(world, iss);
				break;
			case TurnsDataModel::LOADER_TILE_CHARACTER:
				success = loadTile(world, iss);
				break;
			default:
				break;
			}
		}
	}
	loadStream.close();
	if (!success) {
		delete world;
		return NULL;
	}
	return world;
}

void DataLoader::loadPredefinedLands(World *pWorld) {
	Land *grassLand = new Land();
	grassLand->type = UNICOLOR;
	grassLand->color = TurnsDataModel::LAND_GRASS_COLOR;
	grassLand->index = 0;

	Land *water = new Land();
	water->type = WATER;
	// TODO set index when ready and rest of proper indices in this method

	Land *prairieLand = new Land();
	prairieLand->type = UNICOLOR;
	prairieLand->color = TurnsDataModel::LAND_PRAIRIE_COLOR;
	prairieLand->index = 1;

	pWorld->addLand(0, grassLand);
	//pWorld->addLand(1, water);
	pWorld->addLand(2, prairieLand);
}

bool DataLoader::loadCorner(World *pWorld, std::istringstream & pStream) {
	int startX, startY, endX, endY;
	if (!(pStream >> startX >> startY >> endX >> endY)) {
		return false;
	}
	pWorld->setStart(Coord(startX, startY));
	pWorld->setEnd(Coord(endX, endY));
	return true;
}

bool DataLoader::loadLand(World *pWorld, std::istringstream & pStream) {
	int id;
	std::string fileName;
	if (!(pStream >> id >> fileName)) {
		return false;
	}
	if (id < TurnsDataModel::MINIMUM_LAND_ID || pWorld->doesLandExist(id)) {
		return false;
	}
	// TODO: load land
	return true;
}

bool DataLoader::loadObject(World *pWorld, std::istringstream & pStream) {
	int id;
	std::string fileName;
	if (!(pStream >> id >> fileName)) {
		return false;
	}
	if (pWorld->doesObjectExist(id)) {
		return false;
	}

	TileObject *tileObject = new TileObject();

	bool success = true;
	std::string line;
	char character;
	std::ifstream loadStream = std::ifstream(TurnsDataModel::OBJECTS_FILES_PATH_STRING + fileName);
	while (std::getline(loadStream, line) && success) {
		std::istringstream iss(line);
		if (iss >> character) {
			switch (character) {
			case TurnsDataModel::LOADER_COMMENT_CHARACTER:
				break;
			case TurnsDataModel::LOADER_VERTEX_CHARACTER:
				if (line[1] == TurnsDataModel::LOADER_SPACE_CHARACTER) {
					success = loadVertex(&(tileObject->vertexPositions), iss);
				} else if (line[1] == TurnsDataModel::LOADER_TEXTURE_CHARACTER) {
					iss >> character;
					success = loadVertexTextureCoords(&(tileObject->vertexTextureCoords), iss);
				} else {
					success = false;
				}
				break;
			case TurnsDataModel::LOADER_TEXTURE_CHARACTER:
				success = loadTexture(tileObject, iss);
				break;
			case TurnsDataModel::LOADER_FACE_CHARACTER:
				success = loadFace(&(tileObject->vertexIndices), &(tileObject->textureIndices), iss);
				break;
			default:
				break;
			}
		}
	}
	loadStream.close();
	if (!success) {
		return false;
	}
	pWorld->addObject(id, tileObject);

	return true;
}

bool DataLoader::loadTile(World *pWorld, std::istringstream & pStream) {
	int x, y, landId, objectId;
	if (!(pStream >> x >> y >> landId)) {
		return false;
	}
	if (!pWorld->doesLandExist(landId)) {
		return false;
	}
	Land *land = pWorld->findLand(landId);
	Tile *tile = new Tile(land);
	if (pStream >> objectId) {
		TileObject *object = pWorld->findObject(objectId);
		tile->addObject(object);
	}
	pWorld->addTile(Coord(x, y), tile);
	return true;
}

bool DataLoader::loadVertex(std::vector<XMFLOAT3> *pPositions, std::istringstream & pStream) {
	float x, y, z;
	if (!(pStream >> x >> y >> z)) {
		return false;
	}
	pPositions->push_back(XMFLOAT3(x, y, z));
	return true;
}

bool DataLoader::loadVertexTextureCoords(std::vector<XMFLOAT2> *pTextureCoords, std::istringstream & pStream) {
	float x, y;
	if (!(pStream >> x >> y)) {
		return false;
	}
	pTextureCoords->push_back(XMFLOAT2(x, y));
	return true;
}

bool DataLoader::loadTexture(TileObject *pObject, std::istringstream & pStream) {
	std::string fileName;
	if (!(pStream >> fileName)) {
		return false;
	}
	pObject->fileName = fileName;
	if (pStream >> fileName) {
		pObject->filter = fileName;
	}
	return true;
}

bool DataLoader::loadFace(std::vector<DWORD> *pVertexIndices, std::vector<DWORD> *pTextureIndices, std::istringstream & pStream) {
	const int FACE_INDICES = 3;
	std::string first, second, third;
	std::vector<std::string> collection = std::vector<std::string>();
	std::vector<DWORD> currentIndices = std::vector<DWORD>();
	if (!(pStream >> first >> second >> third)) {
		return false;
	}
	collection.push_back(first);
	collection.push_back(second);
	collection.push_back(third);

	for (UINT index = 0; index < FACE_INDICES; ++index) {
		size_t position = collection[index].find(TurnsDataModel::LOADER_SLASH_CHARACTER);
		std::string vertexString = collection[index].substr(0, position);
		std::string textureString = collection[index].substr(position + 1, std::string::npos);
		int vertex = atoi(vertexString.c_str());
		int texture = atoi(textureString.c_str());

		pVertexIndices->push_back(vertex - 1);
		pTextureIndices->push_back(texture - 1);
	}

	return true;
}
